﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using FarseerPhysics.Dynamics;
using PDS2;

namespace ArtificialIntelligence
{
    public enum AIMode
    {
        Strut,
        GoTo,
        Follow,
        GoToArrays,
        FleeFrom
    }
    /// <summary>
    /// Klass av Felix Östh
    /// </summary>
    public class AI
    {
        protected AIMode aiMode;

        public Vector2 Position
        {
            get { return body.Position * 64; }
            set { body.Position = value / 64; }
        }

        public Texture2D Texture;

        public Vector2[] Vectors;

        public Body Body
        {
            get { return body; }
            set { body = value; }
        }

        protected Body body;
        bool debug;

        Color color = Color.White;

        Random random;

        Texture2D blank;

        Vector2 screenSize;

        protected float depth = 0.2f;

        protected Vector2 target;

        protected float velocity = 0;

        float strutTimer;

        bool isFlip;

        public AI(AIMode aiMode) // gjord för follow och fleeFrom
        {
            this.aiMode = aiMode;
        }

        public AI(AIMode aiMode, Random random, Vector2 screenSize) // gjord för strut
        {
            this.random = random;
            this.aiMode = aiMode;
            this.screenSize = screenSize;
            NewTarget();
        }

        public AI(AIMode aiMode, Vector2 goToTarget) // gjord för GoTo
        {
            this.aiMode = aiMode;
            this.target = goToTarget;
        }

        public AI(AIMode aiMode, Vector2[] vectors, bool debug = false, Texture2D blank = null) // gjord för GoToArrays
        {
            if (blank != null)
            {
                this.blank = blank;
                blank.SetData(new[] { Color.White });
            }
            this.aiMode = aiMode;
            this.Vectors = vectors;
            this.Position = vectors[0];
            this.debug = debug;
        }

        public virtual void LoadContent(ContentManager content, string texName)
        {
            Texture = content.Load<Texture2D>(texName);
        }


        int gotoIndex = 1;

        void NewTarget()
        {
            target = new Vector2(random.Next((int)screenSize.X), random.Next((int)screenSize.Y));
        }

        void DrawLine(SpriteBatch batch, Vector2 point1, Vector2 point2, Color color, float width) // lite fina linjer och grejer
        {
            float angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
            float length = Vector2.Distance(point1, point2);

            batch.Draw(blank, point1, null, color, angle, Vector2.Zero, new Vector2(length, width), SpriteEffects.None, 0);
        }

        public virtual void Update(Vector2 position)
        {
            if (Position.X <= target.X)
            {
                isFlip = true;
            }
            else
            {
                isFlip = false;
            }

            switch (aiMode)
            {
                case AIMode.Follow:
                    Follow(position);
                    break;
                case AIMode.Strut:

                    if (Vector2.Distance(target, Position) <= 5)
                    {
                        strutTimer += 0.05f;

                        velocity = 0;

                        if (strutTimer >= 3)
                        {
                            NewTarget();
                            strutTimer = 0;
                        }
                    }

                    if (velocity <= 1.3f)
                    {
                        velocity += 0.2f;
                    }

                    GoTo(target);
                    break;

                case AIMode.GoTo:
                    if(Vector2.Distance(Position,target) > 10)
                        GoTo(target);
                    break;

                case AIMode.GoToArrays:
                    GoTo(Vectors[gotoIndex]);
                    if (Vector2.Distance(Position, Vectors[gotoIndex]) <= 10)
                    {
                        if (gotoIndex == Vectors.Length - 1)
                        {
                            gotoIndex = 0;
                        }
                        else
                            gotoIndex++;
                    }
                    break;
                case AIMode.FleeFrom:
                    if (Vector2.Distance(Position, position) <= 150)
                    { 
                        Vector2 d = Position - position;
                        d.Normalize();
                        body.LinearVelocity = d / 64 * velocity;
                    }
                    break;
            }
        }

        void GoTo(Vector2 target)
        {
            if (Vector2.Distance(target, Position) >= 5)
            {
                Vector2 direction = Vector2.Normalize(target - Position);
                //direction.Normalize();
                //Position += direction * velocity;
                body.LinearVelocity = direction / 64 * velocity;
            }
        }

        float timer()
        {
            return random.Next(0, 5);
        }

        public void Follow(Vector2 target)
        {
            if (aiMode != AIMode.Follow)
                throw new SystemException("Dis nigga ain't up for followin'!");

            if (Vector2.Distance(target, Position) <= 300 && Vector2.Distance(target, Position) >= 1)
            {
                //velocity = 1;
                Vector2 direction = Vector2.Normalize(target - Position);
                //direction.Normalize();
                //Position += direction * velocity;
                body.LinearVelocity = direction / 64 * velocity;

                if (target.X >= Position.X)
                {
                    isFlip = true;
                }
                else
                {
                    isFlip = false;
                }
            }
        }

        public virtual void Draw(SpriteBatch batch)
        {
            if (debug)
            {
                for (int i = 0; i < Vectors.Length; i++)
                {
                    if(i == gotoIndex)
                        batch.Draw(Texture, Vectors[i], null, Color.Black, 0f, Vector2.Zero, 0.17f, SpriteEffects.None, 0f);
                    else
                        batch.Draw(Texture, Vectors[i], null, Color.Black, 0f, new Vector2(64/10,64/10), 0.1f, SpriteEffects.None, 0f);

                    if ((i + 1) >= Vectors.Length)
                    {
                        DrawLine(batch, Vectors[i], Vectors[0], Color.Blue, 1f);
                    }
                    else
                        DrawLine(batch, Vectors[i], Vectors[i + 1], Color.Blue, 1f);
                }
            }

            SpriteEffects spriteEffect = SpriteEffects.None;
            if (!isFlip)
            {
                spriteEffect = SpriteEffects.None;
            }

            if (isFlip)
            {
                spriteEffect = SpriteEffects.FlipHorizontally;
            }

            batch.Draw(Texture, Position, null, color, 0f, new Vector2(Texture.Width / 2), 1f, spriteEffect, Calc.Depth(Position));

        }
    }
}
